/*
 * @Description: ts学习  运行编译：tsc xx文件名
 * @Version: 2.0
 * @Autor: lhl
 * @Date: 2021-05-02 16:13:25
 * @LastEditors: lhl
 * @LastEditTime: 2021-05-02 21:50:08
 */
// 基础类型
// 字符串
let hello:string = "hello word 哈哈"
console.log(hello)

// 布尔
let isBoolean:boolean = true

function add(a:number, b:number) {
  return a + b
}
console.log(add(1,2))

// 数组 元祖（必须要声明类型）
let list1:number[] = [1, 2, 3, 4]
let list2:Array<number> = [1, 2, 3, 4]
let list3 = [1,2,3,4]
let list4:any[] = [1,"abc",true]
let list5: [string, number] = ['1', 2]

// 对象 object
let obj:Object = {
  age: 18,
  sex: "男"
}
// console.log(obj.name) // 定义 Object 还是会有问题
let obj2:{
  age: number,
  sex:string
} = {
  age: 18,
  sex: "男"
}

// 接口 类  访问修饰符
interface IPoint{
  x: number;
  y: number;
  drawPoint: () => void;
  getDistances: (p: IPoint) => number;
}

class Point implements IPoint{
  x: number;
  y: number;
  constructor(x?: number, y?: number) {
    this.x = x;
    this.y = y;
  }
  drawPoint = () => {
    console.log("x:", this.x, "y:", this.y)
  }
  getDistances = (p: IPoint) => {
    return Math.pow(p.x - this.X, 2) + Math.pow(p.y - this.y, 2)
  }
}

const point = new Point(2,3) // 对象实例
point.drawPoint()

// 联合类型
let count: string | number
// count = true // 报错
count = '1'
count = 2

// 字面量类型 {literal}
let selectType: 0 | 1 | 2

// 枚举类型 Enum
enum Color {
  red,
  block,
  blue
}
let color = Color.red
console.log(color,'color') // 0

enum Color2 {
  red = 5,
  block,
  blue
}
let color2 = Color2.block
console.log(color2, 'color2') // 6

//类型适配（断言）
let msg: any
msg = "hello ts"
let str1 = (<string>msg).endsWith("s")
let str2 = (msg as string).endsWith("s")

// 函数类型
let sum1 = function(x: number, y?: number) {
  return x + y
}
let sum2 = function(x: number, y: number) {
  return x + y
}
sum1(1) // 可选
sum2(1, 2) // 必传

// 泛型 单参数
let lastLenArray = <T>(arr: T[]) => {
  return arr[arr.length - 1];
}

const arr1 = lastLenArray<number>([1, 2, 3, 4])
const arr2 = lastLenArray<string>(["1", "2", "3", "4"])
const arr3 = lastLenArray<string | number>([1, "2", "3", 4])

// 多参数
let mutlyTuple = <T, U>(x: T, y: U) => [x, y]

const va11 = mutlyTuple<number, string>(1, '242')
const va12 = mutlyTuple<number,boolean>(1,true)

// interface 与 type 的异同
/**
 *  type 和 interface 的语法不一样，type 需要等号，而 interface 不需要等号
    interface（接口）主要声明的是函数和对象，并且总是需要引入特定的类型
    类型别名声明的可以是任何的数据类型（基本类型别名，联合类型，元组等类型）
 *  接口可以继承类，类型别名不行
    个人习惯：一般来说，如果不清楚什么时候用interface/type，能用 interface 实现，就用 interface , 如果不能就用 type 具体参考官方文档
 *
 */
type UserType = {
  name: String
  age: number
  sayHello: () => void
  sayHi(): void
}

// 扩展 继承
interface Name {
  name: string;
}

interface User extends Name {
  age: number;
}

// type 的扩展
type Man = {
  name: string
}

type Child = Man & { age: number }

// any 和 unknown
let randomVal1: any = 666
randomVal1 = true
randomVal1 = "sytsf"
randomVal1 = {}
// randomVal1()

// 确认了变量类型后才可以使用
let randomVal2: unknown = 666
randomVal2 = true
randomVal2 = "sytsf"
randomVal2 = {}
if (typeof randomVal2 === 'function') {
  randomVal2()
}

// void 、 undefined 、never
function print(): void {
  console.log("balalala")
}
console.log(print(), '看看打印了啥') // undefined

function returnUndefined(): undefined{
  console.log(666)
  return
}
console.log(returnUndefined(), '看看又打印了啥') // undefined

// 永远无法保证完成的状态
function throwError(message:string,erroorCode:number):never {
  throw {
    message,
    erroorCode
   }
}
throwError('not found', 404)

function whileLoop ():never {
  while (true) {
    console.log("object")
  }
}
